package ua.kpi_java_training.zabrodskyi.module2;

/**
 * @author Maksym Zabrodskyi
 * @version 10-Jun-2013
 */
public class Pool {
    private int width;
    private int height;
    private ObjectInPool[] pool;

    public Pool(int width, int height) {
        if (width < 0 || height < 0) {
            throw new RuntimeException("Error: incorrect value.");
        }
        this.width = width;
        this.height = height;
        this.pool = new ObjectInPool[getSize()];
    }

    public void add(ObjectInPool object) {
        for (int index = 0; index < pool.length; index++) {
            if (isFreeUnit(index)) {
                pool[index] = object;
                break;
            }
        }
    }

    public void remove(ObjectInPool object) {
        for (int index = 0; index < pool.length; index++) {
            if (object.equals(pool[index])
                    && object.getPosition().equals(pool[index].getPosition())) {
                pool[index] = null;
                break;
            }
        }
    }

    public ObjectInPool getObject(int index) {
        return pool[index];
    }

    public int getNumberObjects(ObjectInPool object) {
        int number = 0;
        for (int index = 0; index < pool.length; index++) {
            if (object.equals(pool[index])) {
                number++;
            }
        }
        return number;
    }

    public boolean isFreePosition(Position position) {
        boolean free = true;
        for (int index = 0; index < pool.length; index++) {
            if (isBadPosition(position) || !isFreeUnit(index)
                    && position.equals(pool[index].getPosition())) {
                free = false;
                break;
            }
        }
        return free;
    }

    public boolean isBadPosition(Position position) {
        boolean bad = false;
        int x = position.getX();
        int y = position.getY();
        if (x < 0 || x >= width || y < 0 || y >= height) {
            bad = true;
        }
        return bad;
    }

    public boolean hasFreeUnit() {
        boolean free = false;
        for (int index = 0; index < pool.length; index++) {
            if (isFreeUnit(index)) {
                free = true;
                break;
            }
        }
        return free;
    }

    public boolean isSettleObject(ObjectInPool object, Position position) {
        boolean settle = false;
        for (int index = 0; index < pool.length; index++) {
            if (!isFreeUnit(index) && object.equals(pool[index])
                    && position.equals(pool[index].getPosition())) {
                settle = true;
                break;
            }
        }
        return settle;
    }

    public Direction whereNearestObject(ObjectInPool object, Position position) {
        ObjectInPool nearestObject = getObject(findNearestObject(object,
                position));
        int x = nearestObject.getPosition().getX();
        int y = nearestObject.getPosition().getY();
        if ((x - position.getX()) < 0) {
            return Direction.LEFT;
        } else if ((y - position.getY()) < 0) {
            return Direction.UP;
        } else if ((x - position.getX()) > 0) {
            return Direction.RIGHT;
        } else {
            return Direction.DOWN;
        }
    }

    private int findNearestObject(ObjectInPool object, Position newPosition) {
        double minDistance = Double.MAX_VALUE;
        int indexNearestObject = 0;
        for (int index = 0; index < pool.length; index++) {
            if (!isFreeUnit(index) && object.equals(pool[index])) {
                double distance = calculateMinDistance(object.getPosition(),
                        newPosition);
                if (minDistance > distance) {
                    minDistance = distance;
                    indexNearestObject = index;
                }
            }
        }
        return indexNearestObject;
    }

    private double calculateMinDistance(Position position, Position newPosition) {
        return Math.sqrt((Math.pow((position.getX() - newPosition.getX()), 2))
                + (Math.pow((position.getY() - newPosition.getY()), 2)));
    }

    private boolean isFreeUnit(int index) {
        return pool[index] == null;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public int getSize() {
        return width * height;
    }

    @Override
    public String toString() {
        return String.format("Pool = %s [%sx%s]", getSize(), width, height);
    }

}
